use std::borrow::Cow;

/// 写时复制( Copy on Write)技术是一种程序中的优化策略
/// Cow<T>是一个枚举体的智能指针，包括两个可选值:
/// • Borrowed，用于包裹引用。
/// • Owned，用于包裹所有者。
/// 跟 Option<T>类型有点相似， Option<T>表示的是值的“有”和“无”，而 Cow<T>表示 的是所有权的“借用”和“拥有”。
/// Cow<T>提供的功能是，以不可变的方式访问借用内容，以及在需要可变借用或所有权的时候再克隆一份数据。
pub fn start() {
    // 这里没有可变需求，所以不会被克隆
    let s1 = [1, 2, 3];
    let mut i1 = Cow::from(&s1[..]);
    abs_all(&mut i1);
    println!("IN: {:?}", s1);
    println!("OUT: {:?}", i1);

    // 这里有可交需求，所以会克隆
    // s2 != i2 实际上，s2 不可变，也不会被改变
    let s2 = [1, 2, 3, -45, 5];
    let mut i2 = Cow::from(&s2[..]);
    abs_all(&mut i2);
    println!("IN: {:?}", s2);
    println!("OUT: {:?}", i2);

    // 这里不会克险 ，因为数据本身拥有所有权
    // 注意:在本例中，v1本身就是可变的
    let mut v1 = Cow::from(vec![1, 2, 3, 4]);
    abs_all(&mut v1);
    println!("IN/OUT: {:?}", v1);

    //没有可变需求，所以没有克隆
    let s3 = [1, 3, 5, 6];
    let sum1 = abs_sum(&s3[..]);
    println!("{:?}", s3);
    println!("{}", sum1);

    // 这里有可交需求，所以发生了克隆
    let s4 = [-1, 3, -5, 6];
    let sum2 = abs_sum(&s4[..]);
    println!("{:?}", s4);
    println!("{}", sum2);
}

fn abs_all(input: &mut Cow<[i32]>) {
    for i in 0..input.len() {
        let v = input[i];
        if v < 0 {
            input.to_mut()[i] = -v;
        }
    }
}

fn abs_sum(ns: &[i32]) -> i32 {
    let mut lst = Cow::from(ns);
    abs_all(&mut lst);
    lst.iter().fold(0, |acc, &n| acc + n)
}
